#include "stdafx.h"
#include "VixServer.h"

#include <iostream>
#include <string>
#include <list>

#include "vix.h"
#include "VixHandleGuard.h"
#include "VirtualMachine.h"
#include "Utils.h"

using namespace std;
using namespace System;

namespace VirtualOps { namespace Vix {


    void VixServer::Connect(String^ userName, String^ passWord)
    {
        string uri =  Utils::MarshalString(Uri);
        string user = Utils::MarshalString(userName);
        string pass = Utils::MarshalString(passWord);
        // DZ:
        // For WMWare Workstation, when VIX_SERVICEPROVIDER_DEFAULT, 
        // uri and username/password must be blank.
        // When using VIX_SERVICEPROVIDER_VMWARE_WORKSTATION, 
        // uri and username/password ignored.
        VixHandleGuard jobHandleConnect = VixHost_Connect(VIX_API_VERSION,
                          VIX_SERVICEPROVIDER_DEFAULT,//VIX_SERVICEPROVIDER_VMWARE_SERVER,
                          uri.c_str(), // *hostName,
                          0,  // hostPort,
                          user.c_str(), // *userName,
                          pass.c_str(), // *password,
                          0,  //  options,
                          VIX_INVALID_HANDLE, // propertyListHandle,
                          0,  // *callbackProc,
                          0); // *clientData);

	        VixError err = VixJob_Wait(jobHandleConnect, 
                          VIX_PROPERTY_JOB_RESULT_HANDLE, 
                          &_hostHandle,
                          VIX_PROPERTY_NONE);
        if (VIX_OK != err) {
            // VixGetErrorText fails if called from managed code :(
            // const char* errText = Vix_GetErrorText(err, 0); 
            // String^ message = gcnew String(errText);
            String^ message = String::Format("Connect returned error {0}", err);
            throw gcnew VirtualOpsException(message);
        }
    }

    void VixServer::Disconnect()
    {
        VixHost_Disconnect(_hostHandle);
		_hostHandle = VIX_INVALID_HANDLE;
    }


	void VixDiscoveryProc(VixHandle jobHandle,
            VixEventType eventType,
            VixHandle moreEventInfo,
            void *clientData)
    {
        cout<< "VixDiscoveryProc called" << endl;

        VixError err = VIX_OK;
		char* url = NULL;
	    
		list<string>* vmList = (list<string>*)clientData;
		
        // Check callback event; ignore progress reports.
        if (VIX_EVENTTYPE_FIND_ITEM != eventType) {
            return;
        }
		
        // Found a virtual machine.
        err = Vix_GetProperties(moreEventInfo,
            VIX_PROPERTY_FOUND_ITEM_LOCATION,
			&url,
            VIX_PROPERTY_NONE);
		
	        if (VIX_OK != err) {
            // Handle the error...
            // But don't even think of throwing!
            cerr << "Error " << err <<endl;
            cerr << Vix_GetErrorText(err, NULL) << endl; 
            goto abort;
        }
        // TODO: put VMs in the bag...
        cout<< "Found virtual machine: " << url << endl;
		vmList->push_back(url);

		

    abort:
        Vix_FreeBuffer(url);
    }

    array<IVirtualMachine^ >^ VixServer::GetAllVms()
    { 
        if (!Connected) { 
            throw gcnew VirtualOpsException("Must be connected to call this method"); 
        }
        
        cout << "Looking for running virtual machines..." << endl;

		list<string>* vmList = new list<string>;
	
		VixHandleGuard jobHandle = VixHost_FindItems(_hostHandle,
                VIX_FIND_RUNNING_VMS, // TODO: VIX_FIND_REGISTERED_VMS
                VIX_INVALID_HANDLE, // searchCriteria
                -1, // timeout
                VixDiscoveryProc,
                vmList);
        cout << "Wating for completion... " << jobHandle << endl;
        VixError err = VixJob_Wait(jobHandle, VIX_PROPERTY_NONE);
        if (VIX_OK != err) {
            Utils::ThrowVirtualOpsException(err);       
        } else { 
            cout << endl << "done!" << endl;
        }
       int nItems = vmList->size();
		array <VirtualMachine^>^ vmArray = gcnew array<VirtualMachine^>(nItems);
			for(int i=0; i<nItems;i++){
				VixHandleGuard jobHandleOpen = VixVM_Open(_hostHandle,
													vmList->back().c_str(),
													NULL, // VixEventProc *callbackProc,
													NULL); // void *clientData);
				
				VixHandle vmHandle = VIX_INVALID_HANDLE;
				VixError err = VixJob_Wait(jobHandleOpen,
                      VIX_PROPERTY_JOB_RESULT_HANDLE, 
                      &vmHandle,
                      VIX_PROPERTY_NONE);
				if (VIX_OK != err) Utils::ThrowVirtualOpsException(err);
				
				vmArray[i] = gcnew VirtualMachine(vmHandle);
				vmArray[i]->SetProperties();
				vmList->pop_back();
			}
			delete vmList;
		return vmArray;
	
	}

    

    VirtualMachine^ VixServer::GetVmByPath(String^ vmPath)
    {
        string path = Utils::MarshalString(vmPath);
        VixHandleGuard jobHandleOpen = VixVM_Open(_hostHandle,
                           path.c_str(),
                           NULL, // VixEventProc *callbackProc,
                           NULL); // void *clientData);

        VixHandle vmHandle = VIX_INVALID_HANDLE;
        VixError err = VixJob_Wait(jobHandleOpen,
                      VIX_PROPERTY_JOB_RESULT_HANDLE, 
                      &vmHandle,
                      VIX_PROPERTY_NONE);
        if (VIX_OK != err) Utils::ThrowVirtualOpsException(err);

        VirtualMachine^ vm = gcnew VirtualMachine(vmHandle);
        vm->SetProperties();
        return vm;
    }
} } // namespace VirtualOps::Vix
